package com.grapevine.contact.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.ref.SoftReference;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.PriorityBlockingQueue;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.os.Handler.Callback;
import android.text.TextUtils;
import android.widget.TextView;

import com.grapevine.contact.local.NumberLocalProvider;

public class AndroidPhoneLocationLoader implements Callback
{

	private static final int MESSAGE_PHOTOS_LOADED = 0;
	private static final int MESSAGE_REQUEST_LOADING = 1;

	private final ConcurrentHashMap<TextView, String> mPendingRequests = new ConcurrentHashMap<TextView, String>();
	private final ConcurrentHashMap<String, CacheHolder> mPhoneLocationCache = new ConcurrentHashMap<String, CacheHolder>();
	private final PriorityBlockingQueue<String> mRequestLocal = new PriorityBlockingQueue<String>();

	private final Object lock = new Object();

	private final Handler mMainThreadHandler = new Handler(this);

	private static final String LOADER_THREAD_NAME = "ContactNumberLoader";

	private Context mContext;
	private LoaderThread mLoaderThread;
	private LoadFromNet mFromNet;
	private boolean mPaused;
	private boolean mLoadingRequested;

	public AndroidPhoneLocationLoader(Context c)
	{
		mContext = c;
	}

	public void stop()
	{
		pause();
		if (mLoaderThread != null)
		{
			mLoaderThread.quit();
			mLoaderThread = null;
		}

		if (null != mFromNet)
		{
			mFromNet.interrupt();
			mFromNet = null;
		}

		mPendingRequests.clear();
		mPhoneLocationCache.clear();
		mRequestLocal.clear();
	}

	public void pause()
	{
		mPaused = true;
		if (null != mFromNet)
		{
			mFromNet.pause();
		}
	}

	public void resume()
	{
		mPaused = false;
		if (null != mFromNet)
		{
			mFromNet.onResume();
		}
		if (!mPendingRequests.isEmpty())
		{
			requestLoading();
		}
	}

	/**
	 * 动态 加载 号码归属地
	 * @param view
	 * @param number
	 */
	public void loadLocation(TextView view, String number)
	{
		if (TextUtils.isEmpty(number))
		{
			view.setText(number);
			mPendingRequests.remove(view);
		}
		else
		{
			boolean loaded = loadCachedLocation(view, number);
			if (loaded)
			{
				mPendingRequests.remove(view);
			}
			else
			{
				mPendingRequests.put(view, number);
				if (!mPaused)
				{
					requestLoading();
				}
			}
		}
	}

	private void requestLoading()
	{
		if (!mLoadingRequested)
		{
			mLoadingRequested = true;
			mMainThreadHandler.sendEmptyMessage(MESSAGE_REQUEST_LOADING);
		}
	}

	@Override
	public boolean handleMessage(Message msg)
	{

		switch (msg.what)
		{
		case MESSAGE_REQUEST_LOADING:
		{
			if (!mPaused)
			{
				if (null == mLoaderThread)
				{
					mLoaderThread = new LoaderThread(mContext.getContentResolver());
					mLoaderThread.start();
				}

				if (null == mFromNet)
				{
					mFromNet = new LoadFromNet(mContext.getContentResolver());
					mFromNet.start();
				}
				mLoaderThread.requestLoading();
			}
			mLoadingRequested = false;
			return true;
		}

		case MESSAGE_PHOTOS_LOADED:
		{
			if (!mPaused)
			{
				processPhoneLocal();
			}
			return true;
		}
		}

		return false;
	}

	private void processPhoneLocal()
	{
		Iterator<TextView> iterator = mPendingRequests.keySet().iterator();
		while (iterator.hasNext())
		{
			TextView view = iterator.next();
			String phoneNumber = mPendingRequests.get(view);
			boolean loaded = loadCachedLocation(view, phoneNumber);
			if (loaded)
			{
				iterator.remove();
			}
		}

		if (!mPendingRequests.isEmpty())
		{
			requestLoading();
		}
	}

	private boolean loadCachedLocation(TextView view, String number)
	{
		CacheHolder holder = mPhoneLocationCache.get(number);
		if (null == holder)
		{
			holder = new CacheHolder();
			mPhoneLocationCache.put(number, holder);
		}
		else if (holder.state == CacheHolder.LOADED)
		{
			if (null == holder.valueRef)
			{
//				 Log.e(TAG, "load   holder is null!  " + number);
				view.setText(null);
				return true;
			}
			String value = holder.valueRef.get();
			if (!TextUtils.isEmpty(value))
			{
				view.setText(value);
				return true;
			}
			holder.valueRef = null;
//			 Log.e(TAG, "cache  recyle!  " + number);
		}
		view.setText(null);
		holder.state = CacheHolder.NEEDED;
		return false;
	}

	private static class CacheHolder
	{
		private static final int NEEDED = 0;
		private static final int LOADING = 1;
		private static final int LOADED = 2;

		public CacheHolder()
		{
			// TODO Auto-generated constructor stub
		}

		int state;
		SoftReference<String> valueRef;
	}

	private class LoaderThread extends HandlerThread implements Callback
	{
		private final ContentResolver mResolver;
		private final List<String> request = new ArrayList<String>();

		private Handler mLoaderThreadHandler;

		public LoaderThread(ContentResolver resolver)
		{
			super(LOADER_THREAD_NAME);
			mResolver = resolver;
		}

		/**
		 * Sends a message to this thread to load requested photos.
		 */
		public void requestLoading()
		{
			if (null == mLoaderThreadHandler)
			{
				mLoaderThreadHandler = new Handler(getLooper(), this);
			}
			mLoaderThreadHandler.sendEmptyMessage(0);
		}

		/**
		 * Receives the above message, loads photos and then sends a message to
		 * the main thread to process them.
		 */
		public boolean handleMessage(Message msg)
		{
			loadPhotosFromDatabase();
			mMainThreadHandler.sendEmptyMessage(MESSAGE_PHOTOS_LOADED);
			return true;
		}

		private void loadPhotosFromDatabase()
		{
			obtian();
			if (0 == request.size())
			{
				return;
			}

			for (String num : request)
			{
				String location = null;
				Cursor c = mResolver.query(NumberLocalProvider.CONNECT_URI, null, NumberLocalProvider.NUMBER + "='"
						+ num + "'", null, null);
				if (c.moveToFirst())
				{
					String provice = c.getString(c.getColumnIndex(NumberLocalProvider.PROVINCE));
					String city = c.getString(c.getColumnIndex(NumberLocalProvider.CITY));
					location = provice + "  " + city;
				}
				c.close();

				if (TextUtils.isEmpty(location))
				{
					addRequest(num);
				}
				else
				{
					CacheHolder holder = new CacheHolder();
					holder.state = CacheHolder.LOADED;
					holder.valueRef = new SoftReference<String>(location);
					mPhoneLocationCache.put(num, holder);
				}
			}
		}

		private void obtian()
		{
			request.clear();
			Iterator<String> iterator = mPendingRequests.values().iterator();
			while (iterator.hasNext())
			{
				String id = iterator.next();
				CacheHolder location = mPhoneLocationCache.get(id);
				if (null != location && CacheHolder.NEEDED == location.state)
				{
					location.state = CacheHolder.LOADING;
					request.add(id);
				}
			}
		}
	}

	private void addRequest(String num)
	{
		if(!mRequestLocal.contains(num)){
			
			mRequestLocal.put(num);
			
			synchronized (lock)
			{
				lock.notify();
			}
		}
	}

	private class LoadFromNet extends Thread
	{
		private final ContentResolver mResolver;

		public LoadFromNet(ContentResolver resolver)
		{
			mResolver = resolver;
		}

		private boolean isStarting;
//		private CountDownLatch mCountDownLatch;

		public void pause()
		{
//			try
//			{
//				mCountDownLatch.await();
//			}
//			catch (InterruptedException e)
//			{
//			}
		}

		public void onResume()
		{
//			mCountDownLatch.countDown();
		}

		@Override
		public void interrupt()
		{
			isStarting = false;
			super.interrupt();
		}

		@Override
		public synchronized void start()
		{
//			mCountDownLatch = new CountDownLatch(1);
			isStarting = true;
			super.start();
		}

		@Override
		public void run()
		{
			while (isStarting)
			{
				String num = mRequestLocal.poll();
				if (null != num)
				{
					LoadFromNetWork(mResolver, num);
				}
				else
				{
					mMainThreadHandler.sendEmptyMessage(MESSAGE_PHOTOS_LOADED);
					synchronized (lock)
					{
						try
						{
							lock.wait();
						}
						catch (InterruptedException e)
						{
							// e.printStackTrace();
						}
					}
				}
			}
		}
	}

	private void LoadFromNetWork(ContentResolver mResolver, String number)
	{
		String url = "http://api.liqwei.com/location/?mobile=" + number;
		String source = getMethod(url, "GB2312");
//		 System.out.println("source = " + source);
		CacheHolder holder = new CacheHolder();
		holder.state = CacheHolder.LOADED;
		if (!TextUtils.isEmpty(source))
		{
//			holder.state = CacheHolder.LOADED;
			String[] sources = source.split(",");
			if (sources.length > 1)
			{
				ContentValues values = new ContentValues();
				values.put(NumberLocalProvider.NUMBER, sources[0]);
				values.put(NumberLocalProvider.PROVINCE, sources[1]);
				values.put(NumberLocalProvider.CITY, sources[2]);
				values.put(NumberLocalProvider.AREA_CODE, sources[3]);
				values.put(NumberLocalProvider.POST_CODE, sources[4]);
				values.put(NumberLocalProvider.TELCOM, sources[5]);
				values.put(NumberLocalProvider.NETWORK_TYPE, sources[6]);
				mResolver.insert(NumberLocalProvider.CONNECT_URI, values);
				holder.valueRef = new SoftReference<String>(sources[1] + "  " + sources[2]);
			}
			else
			{
//				 Log.e(TAG, "network null! " + number);
			}
		}
		else
		{
			// TODO 这块 可能 需要更改
			holder.state = CacheHolder.LOADED;
		}
		mPhoneLocationCache.put(number, holder);
	}

	private String getMethod(String url, String encod)
	{
		String source = null;
		BufferedReader reader = null;
		try
		{
			URL u = new URL(url);
			HttpURLConnection connection = (HttpURLConnection) u.openConnection();
			connection.setRequestMethod("GET");
			connection.setReadTimeout(10000);
			connection.setConnectTimeout(10000);
			connection.setDoInput(true);
			reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), encod));
			String line = null;
			StringBuilder builder = new StringBuilder();
			while (null != (line = reader.readLine()))
			{
				builder.append(line);
			}
			source = builder.toString();
			connection.disconnect();
		}
		catch (Exception e)
		{
//			e.printStackTrace();
		}
		finally
		{
			if (null != reader)
			{
				try
				{
					reader.close();
				}
				catch (IOException e)
				{
//					e.printStackTrace();
				}
				reader = null;
			}
		}
		return source;
	}
}